package com.java.hohenheim.springplatform.web.security.authentication;

import com.java.hohenheim.springplatform.define.ResultCodes;
import com.java.hohenheim.springplatform.exception.PlatformException;
import com.java.hohenheim.springplatform.web.security.BaseUserAccessControlFilter;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

/**
 * @author LiaoJian, Hohenheim
 * @date 2020/8/24
 * @description 用户Token校验拦截器
 */
public class UserAuthenticationFilter extends BaseUserAccessControlFilter {
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws UnauthorizedException {
        HttpServletRequest req = (HttpServletRequest) request;
        if (req.getMethod().equals(HttpMethod.OPTIONS.toString())) {
            //如果是跨域预请求，就通过该次认证
            return true;
        }

        Subject subject = this.getSubject(request, response);
        return subject.isAuthenticated() && subject.getPrincipal() != null;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest req = (HttpServletRequest) request;

        //如果请求头不存在token,则可能是执行登陆操作或是游客状态访问,直接返回true
        boolean tokenCheckResult = false;
        String token = req.getHeader(HttpHeaders.AUTHORIZATION);
        if(null == token) {
            responseResult(ResultCodes.NOT_LOGGED_ON, response);
        }
        else {
            UserAuthentication authToken = new UserAuthentication(token);
            Subject subject = getSubject(request, response);

            try {
                subject.login(authToken);
                tokenCheckResult = true;
            }
            catch (AuthenticationException e) {
                Throwable throwable = e.getCause();
                if(throwable instanceof PlatformException) {
                    PlatformException platformException = (PlatformException) throwable;
                    responseResult(platformException.getCode(), platformException.getMessage(), response);
                }
                else {
                    responseResult(ResultCodes.TOKEN_EXPIRED, response);
                }
            }
        }

        return tokenCheckResult;
    }
}